package main

import (
	"fmt"
	"time"
)

/*
1. 读取channel的数据时候，如果还没有读到数据会阻塞，一直到有数据进来
	当channel没关闭，读取完后会报错deadlock
	如果关闭，for range 会正常读取完

2. 使用select读取不会阻塞当前线程，如果没读到就进行下一步
	select一般用作处理IO操作的时候的超时处理
*/

func write(intChan chan int) {
	for i := 0; i < 5; i++ {
		intChan <- i
		time.Sleep(time.Second)
	}
	// close(intChan) // 这里不关闭，后面range读取完后会报错
}

// 使用协程来读取，即便没关闭，使用for range也不会报错deadlocak！！！
// 读完了自动退出
func read(intChan chan int) {
	for v := range intChan {
		fmt.Println("读：", v)
	}
}

// 使用select读取不阻塞
// 当从通道读值得时候会发生阻塞，select会按照case顺序执行不阻塞的那个
func readWithoutBlock(intChan chan int) {
	for {
		select {
		case v, ok := <-intChan:
			if ok {
				fmt.Println("读：", v)
			}
		default:
			fmt.Println("读不到，执行其他的！")
			time.Sleep(time.Second) // 此处添加Sleep才会看到效果，否则打印太多了找不到输出
			// break // break只是跳出select循环，可配合lable跳出
			// return
		}
	}
}

func main() {
	intChan := make(chan int, 10)
	go write(intChan)
	// go read(intChan)
	// go readWithoutBlock(intChan)
	// 1. 直接读取，会阻塞（不管是否使用range读取还是普通for循环读取），
	// 因为没使用协程读，取如果没关闭通道，会报错deadlock
	// for v := range intChan {
	// 	fmt.Println("读：", v)
	// }
	for {
		v, ok := <-intChan
		if !ok {
			break
		}
		fmt.Println("读：", v)
	}

	// defer func() {
	// 	err := recover()
	// 	if err != nil {
	// 		fmt.Println("发生了异常！", err)
	// 	}
	// }()
	// time.Sleep(time.Second * 8)
}
